// commodityCollection.js
import { CsDouble } from '../common/csDouble.js';
import { CsFundDouble } from '../common/csFundDouble.js';
import { SubCommodityCollection, SubCommodityCollectionPriceMode } from './subcommodityCollection.js';
import { CommodityBatchWithTax } from '../sales/sales.js';

/**
 * 商品集合操作结果代码
 */
export const CommodityCollectionCode = {
    Succeed: { title: '操作成功', code: 0 },
    CommodityCollectionDuplicated: { title: '商品集重复', code: 1 },
    SubCommodityCollectionDuplicated: { title: '子商品集重复', code: 2 },
    SubCommodityCollectionNotBelongToCommodity: { title: '子商品集不属于商品', code: 3 },
    SubCommodityBatchNotBelongToSubCommodity: { title: '子商品批次数据不属于子商品', code: 4 }
};

/**
 * 单据商品合集
 * 管理商品及其规格商品集合
 */
export class CommodityCollection {
    /**
     * @param {Object} params
     * @param {Commodity} params.commodity 商品
     * @param {Array<SubCommodityCollection>} [params.subCommodityCollection] 初始子商品集合
     */
    constructor({ commodity, subCommodityCollection = [] }) {
        /** @type {Commodity} 商品信息 */
        this.commodity = commodity;

        /** @type {Array<SubCommodityCollection>} 规格商品集合 */
        this._subCommodityCollections = [...subCommodityCollection];
    }

    /**
     * 获取子商品集合列表（只读）
     * @returns {Array<SubCommodityCollection>}
     */
    get subCommmodityCollectionList() {
        return Object.freeze([...this._subCommodityCollections]);
    }

    /**
     * 添加子商品集合
     * @param {SubCommodityCollection} collection 
     * @returns {CommodityCollectionCode}
     */
    addSubCommodityCollection(collection) {
        if (!collection.subCommodity.commodity ||
            collection.subCommodity.commodity.id !== this.commodity.id) {
            return CommodityCollectionCode.SubCommodityCollectionNotBelongToCommodity;
        }

        // 重复检测
        if (this._subCommodityCollections.some(
            item => item.subCommodity.id === collection.subCommodity.id)) {
            return CommodityCollectionCode.SubCommodityCollectionDuplicated;
        }

        this._subCommodityCollections.push(collection);
        return CommodityCollectionCode.Succeed;
    }

    /**
     * 移除子商品集合
     * @param {string} subCommodityId 
     */
    removeSubCommodityCollection(subCommodityId) {
        this._subCommodityCollections = this._subCommodityCollections.filter(
            item => item.subCommodity.id !== subCommodityId
        );
    }

    /**
     * 克隆当前集合
     * @returns {CommodityCollection}
     */
    static clone(data) {
        const cloned = new CommodityCollection({
            commodity: data.commodity
        });

        data._subCommodityCollections.forEach(item => {
            cloned._subCommodityCollections.push(item.clone());
        });

        return cloned;
    }

    /**
     * 获取或创建子商品集合
     * @param {Object} params
     * @param {SubCommodity} params.subCommodity 子商品
     * @param {boolean} params.insertIfNotExist 是否自动插入新记录
     * @param {boolean} [params.initSubCommodityBatch=true] 是否初始化批次
     * @param {SubCommodityCollectionPriceMode} params.priceMode 价格模式
     * @param {CsDouble} params.inventoryCount 库存数量
     * @returns {SubCommodityCollection}
     */
    getOrCreateSubCommodityCollection({
        subCommodity,
        /// 记录不存在，插入记录
        insertIfNotExist,
        /// 如果需要创建 subCommodityCollection 是否初始化 subCommodityBatch
        initSubCommodityBatch = true,
        /// 价格模式
        priceMode,
        /// 库存数量
        inventoryCount,
        /// 是否强制不带税 用于库存操作时不计税价
        withoutTaxForce = false,
    }) {
        let isNewSubCommodityCollection = false;
        let subCollection = this._subCommodityCollections.find(
            item => item.subCommodity.id === subCommodity.id);

        if (!subCollection) {
            isNewSubCommodityCollection = true;
            subCollection = SubCommodityCollection.createWithSubCommodity({
                subCommodity,
                initSubCommodityBatch,
                priceMode,
                inventoryCount,
                /// 是否强制不带税 用于库存操作时不计税价
                withoutTaxForce: withoutTaxForce,
            });

            if (insertIfNotExist) {
                this._subCommodityCollections.push(subCollection);
            }
        }

        /// 已有Subcommodity 但是规格商品批次被删除，添加新批次
        /// todo 如果是合集批次，需要注意该批次是否合适
        if (!isNewSubCommodityCollection &&
            subCollection.subCommmodityBatchList.length === 0) {
            subCollection.addSubCommodityBatchWithTax(new CommodityBatchWithTax({
                commodity: subCommodity,
                count: CsDouble.zero(),
                batchPrice: CsFundDouble.zero(),
                // todo 商品价格目前初始为零售价，后面根据情况更新
                singlePrice: this.commodity.retailPrice
            }));
        }

        return subCollection;
    }

    /**
     * 获取子商品集合
     * @param {string} subCommodityId 
     * @returns {SubCommodityCollection|null}
     */
    getSubCommodityCollection(subCommodityId) {
        return this._subCommodityCollections.find(
            item => item.subCommodity.id === subCommodityId) || null;
    }

    /**
     * 获取商品总数量
     * @returns {CsDouble}
     */
    getCommodityCount() {
        let count = CsDouble.zero();
        this._subCommodityCollections.forEach(item => {
            count = count.add(item.getCommodityCount());
        });
        return count;
    }

    /**
     * 获取商品总价
     * @returns {CsFundDouble}
     */
    getCommodityPrice() {
        let price = CsFundDouble.zero();
        this._subCommodityCollections.forEach(item => {
            price = price.add(item.getCommodityPrice());
        });
        return price;
    }

    /**
     * 获取所有规格商品批次
     * @param {Object} options
     * @param {boolean} [options.zeroInclude=false] 是否包含0数量
     * @returns {Array<CommodityBatchWithTax>}
     */
    getSubCommodityBatches({ zeroInclude = false } = {}) {
        return this._subCommodityCollections.flatMap(item =>
            item.getSubCommodityBatches({ zeroInclude })
        );
    }

    /**
     * 移除规格商品批次
     * @param {CommodityBatchWithTax} batch 
     * @returns {boolean}
     */
    removeSubCommodityBatch(batch) {
        return this._subCommodityCollections.some(item =>
            item.removeSubCommodityBatch(batch)
        );
    }
}